/*
 * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.i360day.common.security;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: liju.z
 * @date: 2023/9/21 16:49
 */
public class UrlUtils {

    /**
     * 判断是否为有效的url
     *
     * @param url
     * @return
     */
    public static boolean isUrl(String url) {
        return isUrl(url, "GET");
    }

    /**
     * 判断是否为有效的url
     *
     * @param url
     * @param method
     * @return
     */
    public static boolean isUrl(String url, String method) {
        StringBuilder result = new StringBuilder();
        try {
            if (StrUtil.isEmpty(method)) method = "GET";
            URL realUrl = new URL(url);
            HttpURLConnection httpUrlConnection = (HttpURLConnection) realUrl.openConnection();
            //设置网络请求时间最多为5秒；
            httpUrlConnection.setConnectTimeout(5000);
            //读取网页请求结果时间为15秒
            httpUrlConnection.setReadTimeout(25000);
            httpUrlConnection.setRequestMethod(method);
            httpUrlConnection.setRequestProperty("accept", "*/*");
            httpUrlConnection.setRequestProperty("connection", "Keep-Alive");
            httpUrlConnection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            httpUrlConnection.connect();
            return httpUrlConnection.getResponseCode() == 200
                    || httpUrlConnection.getResponseCode() == 400;
        } catch (Exception ex) {
            return false;
        }
    }

    private static class TrustAnyTrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    public static InputStream download(String url, String method) {
        try {
            if (StrUtil.isEmpty(method)) method = "GET";
            URL realUrl = new URL(url);
            HttpURLConnection httpUrlConnection = (HttpURLConnection) realUrl.openConnection();
            httpUrlConnection.setInstanceFollowRedirects(true);
            //设置网络请求时间最多为5秒；
            httpUrlConnection.setConnectTimeout(5000);
            //读取网页请求结果时间为15秒
            httpUrlConnection.setReadTimeout(25000);
            httpUrlConnection.setRequestMethod(method);
            httpUrlConnection.setRequestProperty("accept", "*/*");
            httpUrlConnection.setRequestProperty("connection", "Keep-Alive");
            httpUrlConnection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            httpUrlConnection.connect();
            return httpUrlConnection.getInputStream();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static InputStream downloadHttps(String url, String method) {
        try {
            if (StrUtil.isEmpty(method)) method = "GET";
            URL realUrl = new URL(url);
            HttpsURLConnection httpUrlConnection = (HttpsURLConnection) realUrl.openConnection();
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
            httpUrlConnection.setSSLSocketFactory(sc.getSocketFactory());
            httpUrlConnection.setInstanceFollowRedirects(true);
            //设置网络请求时间最多为5秒；
            httpUrlConnection.setConnectTimeout(5000);
            //读取网页请求结果时间为15秒
            httpUrlConnection.setReadTimeout(25000);
            httpUrlConnection.setRequestMethod(method);
            httpUrlConnection.setRequestProperty("accept", "*/*");
            httpUrlConnection.setRequestProperty("connection", "Keep-Alive");
            httpUrlConnection.setRequestProperty("Upgrade-Insecure-Requests", "1");
            httpUrlConnection.setRequestProperty("Sec-Fetch-Site", "none");
            httpUrlConnection.setRequestProperty("Sec-Fetch-Mode", "navigate");
            httpUrlConnection.setRequestProperty("Sec-Fetch-Dest", "document");
            httpUrlConnection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36");
            httpUrlConnection.connect();
            return httpUrlConnection.getInputStream();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 获取重定向地址
     *
     * @param path
     * @return
     * @throws Exception
     */
    public static String getRedirectUrl(String path) {
        try {
            HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
            conn.setInstanceFollowRedirects(false);
            conn.setConnectTimeout(5000);
            String redirectUrl = conn.getHeaderField("Location");
            if (StrUtil.isNotEmpty(redirectUrl)) return redirectUrl;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return path;
    }

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description 获取URL中的参数 <p>
     *
     * <p> @Date  12:50 <p>
     *
     * <p> @Param [url] <p>
     *
     * <p> @return [url] <p>
     **/
    public static Map<String, Object> getUrlParameter(String url) {
        Map<String, Object> params = new HashMap<>();
        if (url.indexOf('?') > 0) {
            String startUrl = url.substring(0, url.indexOf('?') + 1);
            String endUrl = url.substring(startUrl.length(), url.length());
            String[] sp = endUrl.split("&");
            for (String str : sp) {
                if (StrUtil.isEmpty(str)) continue;
                String[] paramsSp = str.split("=");
                if (paramsSp.length == 0) continue;
                String name = str.substring(0, str.indexOf("="));
                String value = str.substring(name.length() + 1, str.length());
                params.put(paramsSp[0], value);
            }
        }
        return params;
    }

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description 组装URL参数 <p>
     *
     * <p> @Date  12:49 <p>
     *
     * <p> @Param [url, params] <p>
     *
     * <p> @return [url, params] <p>
     **/
    public static String getUrlJoint(String url, Map<String, Object> params) {
        if (StrUtil.isEmpty(url)) return url;
        else if (CollUtil.isEmpty(params) || params.isEmpty()) return url;

        if (url.indexOf('?') > 0) {
            String startUrl = url.substring(0, url.indexOf('?') + 1);
            String endUrl = url.substring(startUrl.length(), url.length());
            if (StrUtil.isEmpty(endUrl)) {
                return startUrl + getParamsToString(params);
            }
            if (endUrl.lastIndexOf('&') > 0) {
                return url + getParamsToString(params);
            }
            return url + "&" + getParamsToString(params);
        } else {
            StringBuilder b = new StringBuilder();
            params.forEach((k, v) -> {
                b.append(k).append("=").append(v).append("&");
            });
            if (b.length() > 0) {
                return url + "?" + b.substring(0, b.lastIndexOf("&"));
            }
        }
        return url;
    }

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description 将参数组装成字符串 <p>
     *
     * <p> @Date  12:50 <p>
     *
     * <p> @Param [params] <p>
     *
     * <p> @return [params] <p>
     **/
    private static String getParamsToString(Map<String, Object> params) {
        StringBuilder b = new StringBuilder();
        params.forEach((k, v) -> {
            b.append(k).append("=").append(getURLEncoderString(v.toString())).append("&");
        });
        if (b.length() > 0) {
            return b.substring(0, b.lastIndexOf("&"));
        }
        return b.toString();
    }

    /**
     * <p> @Author liju.z <p>
     *
     * <p> @Description 转换URL参数 <p>
     *
     * <p> @Date  12:50 <p>
     *
     * <p> @Param [str] <p>
     *
     * <p> @return [str] <p>
     **/
    public static String getURLEncoderString(String str) {
        String result = "";
        if (null == str) {
            return "";
        }
        try {
            result = URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }
}
